/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.awt;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Enumeration;
import java.util.Vector;
import javax.swing.*;
import org.openide.util.NbBundle;
import org.openide.awt.JPopupMenuPlus;
/** The SplittedPanel widget is a Panel that can contain one or two components and
* place them side-by-side vertically or horizontally with a splitter in the middle.
* User can move the split point by dragging the splitter with mouse.
* The two components are accessed by add/remove methods with constraints value
* ADD_SPLITTER, ADD_FIRST, ADD_SECOND, ....
* The split position could be either absolute or proportional (according to the
* "Absolute" property setting) - in thwe absolute mode the split point remains same
* when resizing (i.e. the left/top component keeps its size and only the
* right/bottom component resizes), while in the proportional mode the splitPosition
* is a percentage of the width/height assigned to the left/top component.
* <P><TABLE BORDER COLS=3 WIDTH=100%>
* <TR><TH WIDTH=15%>Property<TH WIDTH=15%>Property Type<TH>Description
* <TR><TD> SplitType <TD> int <TD> The type of the splitting - HORIZONTAL, VERTICAL or NONE
* <TR><TD> SplitPosition <TD> int <TD> The position of the split point - either absolute position or number of percents
* according to the "Absolute" property settings, could be one of FIRST_PREFERRED or
* SECOND_PREFERRED, which means that the split point should be placed so that
* the first(left/top) resp. second (bottom/rignt) is sized according to its preferredSize
* (in this case the Absolute property setting is ignored)
* <TR><TD> SplitterType <TD> int <TD> The type of the component that renders the splitter - DEFAULT_SPLITTER, RAISED_SPLITTER,
* EMPTY_SPLITTER.
* <TR><TD> SplitterComponent <TD> Component <TD> The component that renders the splitter. A custom component can be provided in addition to EMPTY_SPLITTER and RAISED-SPLITTER using this method.
* <TR><TD> SplitAbsolute <TD> boolean <TD> if true then the meaning of the SplitPosition is absolute points,
* otherwise the SplitPosition is a number of percents
* <TR><TD> SplitDragable <TD> boolean <TD> if true then the split point can be dragged using a mouse,
* otherwise the SplitPosition is fixed
* <TR><TD> SplitTypeChangeEnabled <TD> boolean<TD> if true then the split type can be changed via popup menu commands
* <TR><TD> SwapPanesEnabled <TD> boolean<TD> if true then the panes can be swapped via popup menu command
* </TABLE>
*
* @author Ian Formanek
*/
public class SplittedPanel extends javax.swing.JComponent {
/** generated Serialized Version UID */
static final long serialVersionUID = 5058424218525927233L;
/** constant for no split - only the first (left/top) component will be shown */
public final static int NONE = 0;
/** constant for vertical split */
public final static int VERTICAL = 1;
/** constant for horizontal split */
public final static int HORIZONTAL = 2;
/** constraints constant for adding a splitter */
public static final Object ADD_SPLITTER = new Integer(0);
/** constraints constant for adding a component to the first (left/top) pane */
public static final Object ADD_FIRST = new Integer(1);
/** constraints constant for adding a component to the second (right/bottom) pane */
public static final Object ADD_SECOND = new Integer(2);
/** constraints constant for adding a component to the left(top) pane (an alias for the ADD_FIRST constant) */
public static final Object ADD_LEFT = ADD_FIRST;
/** constraints constant for adding a component to the top(left) pane (an alias for the ADD_FIRST constant) */
public static final Object ADD_TOP = ADD_FIRST;
/** constraints constant for adding a component to the right(bottom) pane (an alias for the ADD_SECOND constant) */
public static final Object ADD_RIGHT = ADD_SECOND;
/** constraints constant for adding a component to the bottom(right) pane (an alias for the ADD_SECOND constant) */
public static final Object ADD_BOTTOM = ADD_SECOND;
/** constant for moving the split point so that the first (left/top) component is sized according to its preferredSize */
public static final int FIRST_PREFERRED = -1;
/** constant for moving the split point so that the second (right/bottom) component is sized according to its preferredSize */
public static final int SECOND_PREFERRED = -2;
/** constant for splitter component types - raised splitter*/
public static final int RAISED_SPLITTER = 0;
/** constant for splitter component types - empty splitter */
public static final int EMPTY_SPLITTER = 1;
/** constant for splitter component types - default splitter (raised)*/
public static final int DEFAULT_SPLITTER = RAISED_SPLITTER;
/** Constructs a new empty SplittedPanel with no spliting.
*/
public SplittedPanel () {
setLayout (new SplitLayout());
add(splitter, ADD_SPLITTER);
init();
}
/** Initializes the SplittedPanel */
private void init() {
setSplitterCursor();
mouseAdapter = new MouseListenerAdapter();
if (dragable) {
splitter.addMouseMotionListener(mouseAdapter);
splitter.addMouseListener(mouseAdapter);
}
popupMenu = new JPopupMenuPlus();
java.util.ResourceBundle awtBundle = NbBundle.getBundle ("org.openide.awt.Bundle"); // NOI18N
popupMenu.add(verticalCMI = new JCheckBoxMenuItem(awtBundle.getString("SplittedPanelVertical")));
popupMenu.add(horizontalCMI = new JCheckBoxMenuItem(awtBundle.getString("SplittedPanelHorizontal")));
popupMenu.add(new JSeparator());
popupMenu.add(swapCMI = new JMenuItem(awtBundle.getString("SplittedPanelSwap")));
updatePopupMenu();
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (horizontalCMI.equals(e.getSource()))
setSplitType(HORIZONTAL);
else
setSplitType(VERTICAL);
}
};
verticalCMI.addActionListener(al);
horizontalCMI.addActionListener(al);
swapCMI.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
swapPanes();
}
}
);
}
/** Updates splitting, too. */
public void updateUI() {
super.updateUI();
updateSplitting();
}
/** Updates the visual state and layout when the split state changes. */
protected void updateSplitting() {
if (firstComponent != null && secondComponent != null) {
invalidate();
firstComponent.invalidate();
splitter.invalidate();
secondComponent.invalidate();
validate();
}
}
/** Computes component sizes after performing the flip,
* it means splitTypeChange */
protected void computeSizesAfterFlip () {
if (firstComponent == null || secondComponent == null) return;
Dimension ourSize = getSize();
int splitterSize;
switch (splitType) {
case VERTICAL:
if (ourSize.width == 0) break;
splitterSize = splitter.getPreferredSize ().height;
int newHeight = (ourSize.height - splitterSize) *
firstComponent.getSize().width / ourSize.width;
firstComponent.setSize(new Dimension(ourSize.width, newHeight));
secondComponent.setSize(new Dimension(ourSize.width,
ourSize.height - newHeight - splitterSize));
break;
case HORIZONTAL:
if (ourSize.height == 0) break;
splitterSize = splitter.getPreferredSize ().width;
int newWidth = (ourSize.width - splitterSize) *
firstComponent.getSize().height / ourSize.height;
firstComponent.setSize(new Dimension(newWidth, ourSize.height));
secondComponent.setSize(new Dimension(ourSize.width - newWidth - splitterSize,
ourSize.height));
break;
}
}
/** Updates the splitter's cursor according to the current SplittedPanel settings. */
protected void setSplitterCursor() {
if (dragable) {
if (splitType == VERTICAL)
splitter.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
else
splitter.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
}
else
splitter.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
/** Updates the splitter's popup menu. */
protected void updatePopupMenu() {
if (splitType == VERTICAL) {
verticalCMI.setState(true);
horizontalCMI.setState(false);
}
else {
verticalCMI.setState(false);
horizontalCMI.setState(true);
}
if (splitTypeChangeEnabled) {
verticalCMI.setEnabled(true);
horizontalCMI.setEnabled(true);
}
else {
verticalCMI.setEnabled(false);
horizontalCMI.setEnabled(false);
}
if (swapPanesEnabled)
swapCMI.setEnabled(true);
else
swapCMI.setEnabled(false);
}
/** Swaps the panes.*/
public void swapPanes() {
if (!swapPanesEnabled) return;
if ((firstComponent == null) || (secondComponent == null)) return;
splitIsChanging = true;
panesSwapped = !panesSwapped;
if (keepSecondSame) {
keepSecondSame = false;
keepFirstSame = true;
} else if (keepFirstSame) {
keepSecondSame = true;
keepFirstSame = false;
}
Component aFirstComponent = firstComponent;
Component aSecondComponent = secondComponent;
remove(aFirstComponent);
remove(aSecondComponent);
add(aSecondComponent, ADD_FIRST);
add(aFirstComponent, ADD_SECOND);
updateSplitting();
splitIsChanging = false;
}
/** @return true if the panes are swapped, false otherwise */
public boolean getPanesSwapped() {
return panesSwapped;
}
///////////////////////////////
// Property accessor methods //
///////////////////////////////
/** Getter method for the SplitType property.
* @return Current SplitType value.
*/
public int getSplitType() {
return splitType;
}
/** Setter method for the SplitType property.
* @param value New SplitType value.
*/
public void setSplitType(int value) {
if (splitType == value) return;
int oldSplitType = splitType;
splitType = value;
if ((oldSplitType != NONE) && (splitType != NONE))
computeSizesAfterFlip();
setSplitterCursor();
updateSplitting();
updatePopupMenu();
}
/** Getter method for the SplitPosition property.
* @return Current SplitPosition value.
*/
public int getSplitPosition() {
return splitPosition;
}
/** Setter method for the SplitPosition property.
* @param value New SplitPosition value.
*/
public void setSplitPosition(int value) {
if (splitPosition == value) return;
int oldValue = splitPosition;
splitPosition = value;
splitIsChanging = true;
updateSplitting();
fireSplitChange(oldValue, splitPosition);
splitIsChanging = false;
}
/** Getter method for the SplitterType property.
* @return Current SplitterType value.
* @see #EMPTY_SPLITTER
* @see #RAISED_SPLITTER
* @see #DEFAULT_SPLITTER
*/
public int getSplitterType() {
return splitterType;
}
/** Setter method for the SplitterType property.
* @param value New SplitterType value.
* @see #EMPTY_SPLITTER
* @see #RAISED_SPLITTER
* @see #DEFAULT_SPLITTER
*/
public void setSplitterType(int type) {
if (splitterType == type) return;
splitterType = type;
switch (splitterType) {
case EMPTY_SPLITTER:
splitter = new EmptySplitter();
break;
default:
case RAISED_SPLITTER:
splitter = new DefaultSplitter(3);
break;
}
add(splitter, ADD_SPLITTER);
updateSplitting();
}
/** Getter method for the SplitterComponent property.
* @return Current SplitterComponent value.
* @see #getSplitterType
*/
public Component getSplitterComponent() {
return splitter;
}
/** Setter method for the SplitterComponent property.
* @param comp New SplitterComponent value.
* @see #setSplitterType
*/
public void setSplitterComponent(Component comp) {
if (splitter == comp) return;
if (dragable) {
splitter.removeMouseMotionListener(mouseAdapter);
splitter.removeMouseListener(mouseAdapter);
}
remove (splitter);
splitter = comp;
add(splitter, ADD_SPLITTER);
if (dragable) {
splitter.addMouseMotionListener(mouseAdapter);
splitter.addMouseListener(mouseAdapter);
}
setSplitterCursor();
updateSplitting();
}
/** Getter method for the SplitAbsolute property.
* @return Current SplitAbsolute value.
*/
public boolean isSplitAbsolute() {
return absolute;
}
/** Setter method for the SplitAbsolute property.
* @param value New SplitAbsolute value.
*/
public void setSplitAbsolute(boolean value) {
if (absolute == value) return;
absolute = value;
updateSplitting();
}
/** Getter method for the SplitDragable property.
* @return Current SplitDragable value.
*/
public boolean isSplitDragable() {
return dragable;
}
/** Setter method for the Dragable property.
* @param value New Dragable value.
*/
public void setSplitDragable(boolean value) {
if (dragable == value) return;
dragable = value;
if (dragable) {
splitter.addMouseMotionListener(mouseAdapter);
splitter.addMouseListener(mouseAdapter);
}
else {
splitter.removeMouseMotionListener(mouseAdapter);
splitter.removeMouseListener(mouseAdapter);
}
setSplitterCursor();
}
/** Getter method for the ContinuousLayout property.
* @return Current ContinuousLayout value.
*/
public boolean isContinuousLayout() {
return continuousLayout;
}
/** Setter method for the ContinuousLayout property.
* @param value New ContinuousLayout value.
*/
public void setContinuousLayout(boolean value) {
continuousLayout = value;
}
/** Getter method for the KeepFirstSame property.
* @return Current KeepFirstSame value.
*/
public boolean getKeepFirstSame () {
return keepFirstSame;
}
/** Setter method for the KeepFirstSame property.
* @param value New KeepFirstSame value.
*/
public void setKeepFirstSame (boolean value) {
keepFirstSame = value;
}
/** Getter method for the KeepSecondSame property.
* @return Current KeepSecondSame value.
*/
public boolean getKeepSecondSame () {
return keepSecondSame;
}
/** Setter method for the KeepSecondSame property.
* @param value New KeepSecondSame value.
*/
public void setKeepSecondSame (boolean value) {
keepSecondSame = value;
}
/** Getter method for the SplitTypeChangeEnabled property.
* @return Current SplitTypeChangeEnabled value.
*/
public boolean isSplitTypeChangeEnabled() {
return splitTypeChangeEnabled;
}
/** Setter method for the SplitTypeChangeEnabled property.
* @param value New SplitTypeChangeEnabled value.
*/
public void setSplitTypeChangeEnabled(boolean value) {
if (splitTypeChangeEnabled == value) return;
splitTypeChangeEnabled = value;
updatePopupMenu();
}
/** Getter method for the SwapPanesEnabled property.
* @return Current SwapPanesEnabled value.
*/
public boolean isSwapPanesEnabled() {
return swapPanesEnabled;
}
/** Setter method for the SwapPanesEnabled property.
* @param value New SwapPanesEnabled value.
*/
public void setSwapPanesEnabled(boolean value) {
if (swapPanesEnabled == value) return;
swapPanesEnabled = value;
updatePopupMenu();
}
/////////////////////
// Event Listeners //
/////////////////////
/** Adds specified listener to the current set of SplitChangeListeners */
public void addSplitChangeListener(SplitChangeListener l) {
if (listeners == null)
listeners = new Vector();
listeners.addElement(l);
}
/** Removes specified listener from the current set of SplitChangeListeners */
public void removeSplitChangeListener(SplitChangeListener l) {
if (listeners == null)
return;
listeners.removeElement(l);
}
/** Fires the SplitChange event */
protected void fireSplitChange(int oldValue, int newValue) {
if (listeners == null)
return;
Vector l;
synchronized (this) {
l = (Vector)listeners.clone();
}
Enumeration en = l.elements ();
SplitChangeEvent evt = new SplitChangeEvent (this, oldValue, newValue);
while (en.hasMoreElements ()) {
SplitChangeListener scl = (SplitChangeListener) en.nextElement ();
scl.splitChanged(evt);
}
}
///////////////////
// Inner Classes //
///////////////////
/** A listener interface for tracking split point changes */
public static interface SplitChangeListener {
/** Called when a split point changes
* @param evt The SplitChangeEvent that describes the change
*/
public void splitChanged (SplitChangeEvent evt);
}
/** An event that describes a split point change */
public static class SplitChangeEvent extends java.util.EventObject{
/** generated Serialized Version UID */
static final long serialVersionUID = 6748966611210836878L;
private int oldValue, newValue;
/** Constructs a new SplitChangeEvent for specified source SplittedPanel and
* old and new SplitPositions
*/
public SplitChangeEvent (SplittedPanel splittedPanel, int oldValue, int newValue) {
super(splittedPanel);
this.oldValue = oldValue;
this.newValue = newValue;
}
/** @return the old splitterPosition */
public int getOldValue() {
return oldValue;
}
/** @return the new splitterPosition */
public int getNewValue() {
return newValue;
}
}
/** The EmptySplitter is an empty splitter component with specified width.
* It can be used as the splitter via setSplitterComponent.
*/
public static class EmptySplitter extends JComponent {
/** generated Serialized Version UID */
static final long serialVersionUID = 929648193440460693L;
private int width;
public EmptySplitter () {
this (0);
}
public EmptySplitter (int width) {
this.width = width;
}
public Dimension getPreferredSize() {
return new Dimension (width, width);
}
}
/** The DefaultSplitter class implements a splitting line that is to be used as a default splitter for the SplittedPanel.
* It paints a raised 3D-line with given width.
*/
class DefaultSplitter extends JComponent {
private int splitterSize;
static final long serialVersionUID =-4223135481223014719L;
/**
* Constructs a new DefaultSplitter with given width.
* @param aWidth the desired width of the splitting line, if the value is lower than 2, the width of 2 is used
*/
public DefaultSplitter(int aSplitterSize) {
splitterSize = aSplitterSize;
if (splitterSize < 2) splitterSize = 2;
}
public Dimension getPreferredSize() {
return new Dimension (splitterSize, splitterSize);
}
public void paint(Graphics g) {
Dimension size = getSize();
if (splitType == HORIZONTAL) {
int pos = (size.width-splitterSize) / 2;
g.setColor(SystemColor.controlLtHighlight);
g.drawLine(pos, 0, pos, size.height - 1);
g.setColor(SystemColor.control);
for (int i = 1; i < splitterSize - 2; i++)
g.drawLine(pos+i, 0, pos + i, size.height - 1);
g.setColor(SystemColor.controlDkShadow);
g.drawLine(pos + splitterSize - 1, 0, pos + splitterSize - 1, size.height - 1);
}
else if (splitType == VERTICAL) {
int pos = (size.height-splitterSize) / 2;
g.setColor(SystemColor.controlLtHighlight);
g.drawLine(0, pos, size.width - 1, pos);
g.setColor(SystemColor.control);
for (int i = 1; i < splitterSize-2; i++)
g.drawLine(0,pos + i, size.width - 1, pos + i);
g.setColor(SystemColor.controlDkShadow);
g.drawLine(0, pos + splitterSize - 1, size.width - 1, pos + splitterSize - 1);
}
}
}
/**
* The MouseListenerAdapter class implements the dragging behaviour of the splitter.
*/
class MouseListenerAdapter extends java.awt.event.MouseAdapter implements MouseListener, MouseMotionListener {
/** A method implemented from the MouseListener interface to handle the splitter dragging */
public void mousePressed(MouseEvent e) {
// if (e.isPopupTrigger())
if ((e.getModifiers() & e.BUTTON3_MASK) != 0)
popupMenu.show(splitter, e.getX(), e.getY());
else
dragging = true;
}
/** A method implemented from the MouseListener interface to handle the splitter dragging */
public void mouseReleased(MouseEvent e) {
if (dragging == true && continuousLayout == false) {
dragging = false;
if (dragPos == -1) return;
if (!absolute) {
Dimension d = getSize();
if (splitType == VERTICAL)
dragPos = (100 * dragPos)/d.height;
else
dragPos = (100 * dragPos)/d.width;
}
setSplitPosition(dragPos);
dragPos = -1;
}
}
/** A method implemented from the MouseMotionListener interface to handle the splitter dragging */
public void mouseDragged(MouseEvent e) {
if (dragging == true && continuousLayout == true) {
Dimension d = getSize();
Point splitterPos = splitter.getLocation();
e.translatePoint(splitterPos.x, splitterPos.y);
if (splitType == VERTICAL) {
dragPos = e.getY();
if (dragPos > d.height) dragPos = d.height;
}
else {
dragPos = e.getX();
if (dragPos > d.width) dragPos = d.width;
}
if (dragPos < 0) dragPos = 0;
if (continuousLayout) {
if (dragPos == -1) return;
int newDragPos = dragPos;
if (!absolute) {
if (splitType == VERTICAL)
newDragPos = (100 * dragPos)/d.height;
else
newDragPos = (100 * dragPos)/d.width;
}
setSplitPosition(newDragPos);
}
}
}
/** A method implemented from the MouseMotionListener interface to handle the splitter dragging */
public void mouseMoved(MouseEvent e) {
}
}
/**
* The SplitLayout class implements a LayoutManager for the SplittedPanel.
*/
class SplitLayout extends Object implements LayoutManager2, java.io.Serializable {
static final long serialVersionUID =2034500275182524789L;
public void addLayoutComponent (String name, Component comp) {
throw new IllegalArgumentException("You must use the add(Component, Object) method for adding"); // NOI18N
}
public void addLayoutComponent(Component comp, Object constraints) {
if (constraints == ADD_SPLITTER) // adding a splitter
splitter = comp;
else if (constraints == ADD_FIRST) { // adding to the left/top
if ((firstComponent != null) && (secondComponent == null)) // if we altready have ... [PENDING]
secondComponent = firstComponent;
firstComponent = comp;
if ((secondComponent != null) && (splitType == NONE))
splitType = DEFAULT_SPLIT_TYPE;
}
else if (constraints == ADD_SECOND) {
if (firstComponent == null)
firstComponent = comp;
else {
secondComponent = comp;
if (splitType == NONE)
splitType = DEFAULT_SPLIT_TYPE;
}
}
else throw new IllegalArgumentException("You must use one of the SplittedPanel.ADD_XXX constraints Objects"); // NOI18N
}
public void removeLayoutComponent (Component comp) {
if (comp.equals(secondComponent))
secondComponent = null;
else if (comp.equals(firstComponent)) {
firstComponent = null;
if (secondComponent != null) {
firstComponent = secondComponent;
secondComponent = null;
}
}
}
public Dimension preferredLayoutSize (Container parent) {
int width = 0;
int height = 0;
if (firstComponent != null) {
Dimension d = firstComponent.getPreferredSize();
width = d.width;
height = d.height;
}
if (secondComponent != null) {
Dimension d = secondComponent.getPreferredSize();
if (splitType == VERTICAL) {
int splitterSize = splitter.getPreferredSize ().height;
if (width < d.width) width = d.width;
height += splitterSize + d.height;
}
else {
int splitterSize = splitter.getPreferredSize ().width;
if (height < d.height) height = d.height;
width += splitterSize + d.width;
}
}
return new Dimension(width, height);
}
public Dimension minimumLayoutSize (Container parent) {
int width = 0;
int height = 0;
if (firstComponent != null) {
Dimension d = firstComponent.getPreferredSize();
width = d.width;
height = d.height;
}
if (secondComponent != null) {
Dimension d = secondComponent.getPreferredSize();
if (splitType == VERTICAL) {
int splitterSize = splitter.getPreferredSize ().height;
if (width < d.width) width = d.width;
height += splitterSize + d.height;
}
else {
int splitterSize = splitter.getPreferredSize ().width;
if (height < d.height) height = d.height;
width += splitterSize + d.width;
}
}
return new Dimension(width, height);
}
public void layoutContainer (Container parent) {
Dimension d = parent.getSize();
int sPosition = splitPosition;
// 1. first preferred
if (splitPosition == FIRST_PREFERRED) {
if (splitType == VERTICAL)
sPosition = firstComponent.getPreferredSize().height;
else
sPosition = firstComponent.getPreferredSize().width;
// 2. second preferred
} else if (splitPosition == SECOND_PREFERRED) {
if (splitType == VERTICAL) {
sPosition = d.height - splitter.getPreferredSize ().width - secondComponent.getPreferredSize().height;
} else {
sPosition = d.width - splitter.getPreferredSize ().height - secondComponent.getPreferredSize().width;
}
// 3. percent position
} else if (!absolute) {
int sp = splitPosition;
if (sp > 100) sp = 100;
if (splitType == VERTICAL)
sPosition = (d.height * sp) / 100;
else
sPosition = (d.width * sp) / 100;
}
if ((splitType != NONE) && (firstComponent != null) && (secondComponent != null)) { // splitted
if (splitType == VERTICAL) {
int splitterSize = splitter.getPreferredSize ().height;
if (keepSecondSame && !splitIsChanging) {
Dimension secondSize = secondComponent.getSize ();
if (secondSize.height != 0)
sPosition = d.height - secondSize.height - splitterSize;
}
if (sPosition + splitterSize > d.height)
sPosition = d.height - splitterSize;
if (sPosition < 0)
sPosition = 0;
firstComponent.setBounds(new Rectangle(0, 0, d.width, sPosition));
splitter.setBounds(new Rectangle(0, sPosition, d.width, splitterSize));
secondComponent.setBounds(new Rectangle(0, sPosition + splitterSize, d.width, d.height - sPosition - splitterSize));
}
else {
int splitterSize = splitter.getPreferredSize ().width;
if (keepSecondSame && !splitIsChanging) {
Dimension secondSize = secondComponent.getSize ();
if (secondSize.width != 0)
sPosition = d.width - secondSize.width - splitterSize;
}
if (sPosition + splitterSize > d.width)
sPosition = d.width - splitterSize;
if (sPosition < 0)
sPosition = 0;
firstComponent.setBounds(new Rectangle(0, 0, sPosition, d.height));
splitter.setBounds(new Rectangle(sPosition, 0, splitterSize, d.height));
secondComponent.setBounds(new Rectangle(sPosition + splitterSize, 0, d.width - sPosition - splitterSize, d.height));
}
}
else if (firstComponent != null) {
firstComponent.setBounds (new Rectangle(0, 0, d.width-1, d.height -1));
if (splitter != null)
splitter.setBounds (0, 0, 0, 0);
}
}
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
public float getLayoutAlignmentX(Container target) { return 0; }
public float getLayoutAlignmentY(Container target) { return 0; }
public void invalidateLayout(Container target) {}
}
/** Deserializes the component and initializes it. */
private void readObject(java.io.ObjectInputStream ois)
throws java.io.IOException, ClassNotFoundException {
ois.defaultReadObject();
init();
}
///////////////////////
// Private variables //
///////////////////////
/** the first (left/top) component */
private Component firstComponent = null;
/** the second (right/bottom) component */
private Component secondComponent = null;
/** the splitter component */
private Component splitter = new DefaultSplitter(3);
/** the splitter component type */
private int splitterType = DEFAULT_SPLITTER;
/** the mouse adapter that does the dragging of the splitter*/
private transient MouseListenerAdapter mouseAdapter;
/** current split type */
private int splitType = NONE;
/** current split position */
private int splitPosition = 50;
private boolean absolute = false;
private boolean dragable = true;
private boolean continuousLayout = true;
/** current enabled/disabled state of change of split type */
private boolean splitTypeChangeEnabled = true;
/** current enabled/disabled state of change of swapping panes */
private boolean swapPanesEnabled = true;
/** current keepSecondSame state - this has bigger priority than keepFirstSame */
private boolean keepSecondSame = false;
/** current keepFirstSame state */
private boolean keepFirstSame = false;
transient private boolean splitIsChanging = false;
private int dragPos = -1;
private boolean dragging = false;
/** true if the panes were swapped, false otherwise */
private boolean panesSwapped = false;
/** The default split type */
private final static int DEFAULT_SPLIT_TYPE = HORIZONTAL;
/** The default splitter size */
private final static int DEFAULT_SPLITTER_SIZE = 7;
/** popup menu for setting vertical/horizontal splitting */
transient private JPopupMenu popupMenu;
/** The popup menu item */
transient private JCheckBoxMenuItem verticalCMI;
/** The popup menu item */
transient private JCheckBoxMenuItem horizontalCMI;
/** The popup menu item */
transient private JMenuItem swapCMI;
/** A Vector of SplitChangeListeners
* @associates SplitChangeListener*/
transient private Vector listeners;
}
/*
* Log
* 13 Gandalf 1.12 3/11/00 Martin Ryzl menufix [by E.Adams,
* I.Formanek]
* 12 Gandalf 1.11 1/12/00 Ian Formanek NOI18N
* 11 Gandalf 1.10 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 10 Gandalf 1.9 8/9/99 Ian Formanek Generated Serial Version
* UID
* 9 Gandalf 1.8 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 8 Gandalf 1.7 5/7/99 Ian Formanek Fixed using non-default
* splitter components
* 7 Gandalf 1.6 5/6/99 Jan Jancura
* 6 Gandalf 1.5 4/30/99 Ian Formanek Added splitterComponent
* property, EmptySplitter can be used with non-zero width.
* 5 Gandalf 1.4 3/9/99 Jaroslav Tulach Node actions releases
* sometimes its listeners.
* 4 Gandalf 1.3 3/8/99 Jaroslav Tulach Bundles.
* 3 Gandalf 1.2 3/8/99 Ian Formanek Removed unused imports
* 2 Gandalf 1.1 1/6/99 Ian Formanek Reflecting changes in
* location of package "awt"
* 1 Gandalf 1.0 1/5/99 Ian Formanek
* $
* Beta Change History:
* 0 Tuborg 0.21 --/--/98 Jan Formanek repaired the "catch the focus" bug
* 0 Tuborg 0.25 --/--/98 Jan Formanek SplitLayout made serializable
* 0 Tuborg 0.26 --/--/98 Jan Formanek mouseAdapter made transient, readObject implemented appropriately
* 0 Tuborg 0.30 --/--/98 Jan Formanek renamed properties Absolute, Dragable to SplitAbsolute, SplitDragable
* 0 Tuborg 0.31 --/--/98 Jan Formanek small layout fix
* 0 Tuborg 0.32 --/--/98 Jan Formanek getPanesSwapped method added
* 0 Tuborg 0.33 --/--/98 Jan Formanek SplitChangeListeners added
* 0 Tuborg 0.33 --/--/98 Jan Formanek moving splitter outside visible area bug fixed (BUG #04100005)
*/